package baseObjectContract;
import assertTools.DecoratorTools;
import baseObject.BaseObjectsFactory;
import baseObject.IBall;
import baseObject.IBrickBreaker;
import baseObject.IRectObj;
import baseObject.RectObj;
import baseObjectDecorator.RectObjDecorator;

public class RectObjContract extends RectObjDecorator{
	private RectObj rectObj;
	private IBall theBall;
	
	public RectObjContract(RectObj rectObj) {
		super(rectObj);
		this.rectObj = rectObj;
	}
	
	public void init(int x, int y, int width, int height) {
		DecoratorTools.checkPre(x >= 0 || y >= 0 || width >= 0 || height >= 0);
		//NOTE: Pourquoi un || et pas un && ?
		DecoratorTools.checkPre(x + width <= IBrickBreaker.XMAX || y + height <= IBrickBreaker.YMAX);
		
		this.theBall = BaseObjectsFactory.newBall(x, y, width, height); // Only here in order to test the invariant
		
		this.rectObj.init(x, y, width, height);
		
		DecoratorTools.checkPost(super.getX() == x && super.getY() == y);
		//TODO: Ajouter les vérifications pour width et height 
		
		this.checkInvariantRectObj();
	}
	
	private void checkInvariantRectObj(){
		//DecoratorTools.checkInv(super.getX() >= 0 && super.getX() <= IBrickBreaker.XMAX);
		//DecoratorTools.checkInv(super.getY() >= 0 && super.getY() <= IBrickBreaker.YMAX);
		DecoratorTools.checkInv(this.getX() + this.getWidth() 
				<= IBrickBreaker.XMAX && this.getY() + this.getHeight() <= IBrickBreaker.YMAX);
		
		if(super.getHitState(this.theBall) != eHitType.NO)
			DecoratorTools.checkInv(super.isAffectedBy(this.theBall));
		if(super.getHitState(this.theBall) == eHitType.NO)
			DecoratorTools.checkInv(!super.isAffectedBy(this.theBall));
		if(this.theBall.getDeltaX() == -1 && super.isAffectedBy(this.theBall))
			DecoratorTools.checkInv(super.getHitState(this.theBall) == eHitType.RIGHT);
		if(this.theBall.getDeltaX() == 1 && super.isAffectedBy(this.theBall))
			DecoratorTools.checkInv(super.getHitState(this.theBall) == eHitType.LEFT);
		if(this.theBall.getDeltaY() == 1 && super.isAffectedBy(this.theBall))
			DecoratorTools.checkInv(super.getHitState(this.theBall) == eHitType.UP);
		if(this.theBall.getDeltaY() == -1 && super.isAffectedBy(this.theBall))
			DecoratorTools.checkInv(super.getHitState(this.theBall) == eHitType.DOWN);
		if(!super.isAffectedBy(this.theBall))
			DecoratorTools.checkInv(super.getHitState(this.theBall) == eHitType.NO);	
	}
	
	public boolean isAffectedBy(IRectObj iRectObj) {
		return super.isAffectedBy(iRectObj);
	}

	public eHitType getHitState(IBall ball) {
		return super.getHitState(ball);
	}

	public int getX() {
		return super.getX();
	}

	public int getY() {
		return super.getY();
	}

	public void setCoord(int x, int y) {
		this.checkInvariantRectObj();
		
		DecoratorTools.checkPre(x >= 0 && y >= 0);
		DecoratorTools.checkPre(x <= IBrickBreaker.XMAX && y <= IBrickBreaker.YMAX);
		//TODO : revoir l'accès à XMAX... celui de dessus est une constante alors qu'on passe en paramètre XMAX au Brikeout
		DecoratorTools.checkInv(x + this.getWidth() 
				<= IBrickBreaker.XMAX && y + this.getHeight() <= IBrickBreaker.YMAX);
		super.setCoord(x, y);
		
		DecoratorTools.checkPost(super.getX() == x && super.getY() == y);
		
		this.checkInvariantRectObj();
	}

	@Override
	public Object cloneObj() {
		return this.cloneObj();
	}
}
